package org.visionlibrary.image.filters.labeling;

import java.util.HashSet;
import java.util.Set;

import javax.media.jai.TiledImage;

import org.visionlibrary.image.geomtric.model.Mask2d;
import org.visionlibrary.image.geomtric.model.Point2d;
import org.visionlibrary.image.model.AbstractFilter;


public class SimpleIndexing extends AbstractFilter {
	public static final int[] DEFAULT_BACKGROUND = new int[] { 255, 255, 255 };
	private Mask2d mask;

	private int xLength;
	private int yLength;

	private int[] background; // TODO mylnie przyjmujemy jaki jest color space

	private int found = 0;
	private Set<Point2d> pts = new HashSet<Point2d>();

	private int minSize;
	private int maxSize;
	
	public SimpleIndexing() {
		this(0, Integer.MAX_VALUE, SimpleIndexing.DEFAULT_BACKGROUND);
	}

	public SimpleIndexing(int minSize, int maxSize, int[] background) {
		this.background = background;
		this.minSize = minSize;
		this.maxSize = maxSize;
	}

	private int grow() {
		int size = 1;
		do {
			Set<Point2d> newPts = new HashSet<Point2d>();
			for (Point2d p : pts) {
				int x = p.getXAsInt();
				int y = p.getYAsInt();

				if (x > 0 && mask.get(x - 1, y)) {
					mask.unSet(x - 1, y);
					newPts.add(new Point2d(x - 1, y));
					++size;
				}
				if (x < xLength - 1 && mask.get(x + 1, y)) {
					mask.unSet(x + 1, y);
					newPts.add(new Point2d(x + 1, y));
					++size;
				}
				if (y > 0 && mask.get(x, y - 1)) {
					mask.unSet(x, y - 1);
					newPts.add(new Point2d(x, y - 1));
					++size;
				}
				if (y < yLength - 1 && mask.get(x, y + 1)) {
					mask.unSet(x, y + 1);
					newPts.add(new Point2d(x, y + 1));
					++size;
				}
			}
			pts = newPts;
		} while (!pts.isEmpty());
		return size;
	}

	public int count() {
		return found;
	}

	@Override
	public TiledImage applyFilter(TiledImage src, TiledImage dest) {
		if (null == src)
			throw new NullPointerException("Source image is null.");

		if (null != dest)
			throw new IllegalArgumentException("Destination image shouldnt be specified.");

		if(null == background)
			throw new NullPointerException("Background color not specified.");
		
		if(0 == background.length)
			throw new IllegalArgumentException("Background color not specified.");
		
		this.mask = Mask2d.createForegroundMask(src, background);

		this.xLength = mask.width();
		this.yLength = mask.height();

		pts.clear();

		for (int x = 0; x < xLength; ++x) {
			for (int y = 0; y < yLength; ++y) {
				if (mask.get(x, y)) {
					mask.unSet(x, y);
					pts.add(new Point2d(x, y));
					int size = grow();
					if (size > minSize) {
						continue;
					}
					int items = size / maxSize;
					if (items == 0) {
						++items;
					}
					found += items;
				}
			}
		}
		
		return null;
	}
}
